package com.yjzx.util.service.pay.strategy.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.yjzx.util.service.pay.config.properties.AlipayProperties;
import com.yjzx.util.service.pay.constants.BaseConstant;
import com.yjzx.util.service.pay.enums.ClientEnum;
import com.yjzx.util.service.pay.strategy.OrderInterface;
import com.yjzx.util.service.pay.strategy.PayStrategy;
import com.yjzx.util.service.pay.strategy.PaySuccessParam;
import com.yjzx.util.common.util.HttpUtils;
import com.yjzx.util.common.util.TimeUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

/**
 * @author yjzx
 * @Description 支付宝
 * @create 2022-12-28 22:40
 */
@Slf4j
@Component
public class AlipayStrategy implements PayStrategy {
    @Getter
    final private String name = "alipay";
    final private AlipayProperties alipayProperties;
    final private Map<String, AlipayClient> alipayClients;

    @Autowired
    public AlipayStrategy(Map<String, AlipayClient> alipayClient, AlipayProperties alipayProperties) {
        this.alipayClients = alipayClient;
        this.alipayProperties = alipayProperties;
    }

    private AlipayClient getAlipayClient(ClientEnum clientEnum) {
        AlipayClient alipayClient;
        switch (clientEnum) {
            case APP:
                alipayClient = this.alipayClients.get("alipayAppClient");
                break;
            case MINI:
                alipayClient = this.alipayClients.get("alipayMiniClient");
                break;
            case HTML:
            default:
                alipayClient = this.alipayClients.get("alipayHtmlClient");
        }
        return alipayClient == null ? getAlipayClient(ClientEnum.getDefaultClient()) : alipayClient;
    }

    private AlipayProperties.AliApplication getApplication(ClientEnum clientEnum) {
        AlipayProperties.AliApplication application;
        switch (clientEnum) {
            case APP:
                application = this.alipayProperties.getApp();
                break;
            case MINI:
                application = this.alipayProperties.getMini();
                break;
            case HTML:
            default:
                application = this.alipayProperties.getHtml();
        }
        return application == null ? getApplication(ClientEnum.getDefaultClient()) : application;
    }


    /**
     * 为某个订单展示收银台页面
     *
     * @param orderInfo 订单详情
     * @return 支付页面
     */
    @Override
    public String cashierPage(OrderInterface orderInfo) {

        ClientEnum clientEnum = orderInfo.getClientEnum();
        AlipayProperties.AliApplication application = getApplication(clientEnum);
        AlipayClient client = getAlipayClient(clientEnum);

        //2、创建一个支付请求
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();


        //3、设置参数
        if (ClientEnum.HTML.equals(clientEnum)) {
            //同步回调：支付成功以后，浏览器要跳转到的页面地址
            alipayRequest.setReturnUrl(alipayProperties.getReturnUrl());
        }

        //通知回调：支付成功以后，支付消息会通知给这个地址
        alipayRequest.setNotifyUrl(application.getNotifyUrl());


        //商户订单号（对外交易号）
        String outTradeNo = orderInfo.getOutTradeNo();
        //付款金额
        BigDecimal totalAmount = orderInfo.getPrice();
        //订单名称
        String orderName = orderInfo.getOrderName();
        //商品描述
        String tradeBody = orderInfo.getDesc();
        Date expireTime = orderInfo.getExpireTime();
        //自动关单
        String date = TimeUtils.dateTimeToString(expireTime);

        //详细：https://opendocs.alipay.com/open/028r8t?scene=22


        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(tradeBody);
        model.setSubject(orderName);
        model.setOutTradeNo(outTradeNo);
        model.setTimeoutExpress(date);
        model.setTotalAmount(totalAmount.toPlainString());
        String response;
        try {
            switch (clientEnum) {
                case APP:
                    model.setProductCode("QUICK_MSECURITY_PAY");
                    alipayRequest.setBizModel(model);
                    response = client.sdkExecute(alipayRequest).getBody();
                    break;
                case MINI:
                    alipayRequest.setBizModel(model);
                    response = client.execute(alipayRequest).getBody();
                    break;
                case HTML:
                default:
                    model.setProductCode("FAST_INSTANT_TRADE_PAY");
                    alipayRequest.setBizModel(model);
                    response = client.pageExecute(alipayRequest).getBody();
            }
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }


        return response;
    }

    /**
     * 验证签名
     *
     * @param request    原生请求
     * @param body       请求体数据
     * @param clientEnum
     * @return
     */
    @Override
    public boolean checkSign(HttpServletRequest request, String body, ClientEnum clientEnum) {
        Map<String, String> params = HttpUtils.getParameterMap(request);
        log.info("支付宝通知验证签名...");
        AlipayProperties.AliApplication application = getApplication(clientEnum);
        //验证签名
        try {
            //调用SDK验证签名
            return AlipaySignature.rsaCheckV1(params,
                    application.getAlipayPublicKey(), alipayProperties.getCharset(),
                    alipayProperties.getSignType());
        } catch (AlipayApiException e) {
        }
        return false;
    }

    /**
     * 验签错误处理
     *
     * @return
     */
    @Override
    public Object signError() {
        return "error";
    }

    /**
     * 验签成功后处理通知数据： 把通知的所有数据封装指定对象
     *
     * @param request
     * @return
     */
    @Override
    public PaySuccessParam process(HttpServletRequest request, String body) {
        Map<String, String> map = JSON.parseObject(body, new TypeReference<Map<String, String>>() {
        });
        if ("trade_status_sync".equals(map.get("notify_type"))
                && BaseConstant.TRADE_SUCCESS.equals(map.get("trade_status"))
        ) {
            PaySuccessParam successParam = new PaySuccessParam();
            successParam.setOrderNum(map.get("out_trade_no"));
            successParam.setOutNum(map.get("trade_no"));
            successParam.setPayTime(TimeUtils.stringToDateTime(map.get("gmt_payment")));
            successParam.setPayAccount(map.get("buyer_logon_id"));
            return successParam;
        }
        return null;

    }

    /**
     * 退单处理
     *
     * @param orderId    订单id
     * @param clientEnum
     * @return
     */
    @Override
    public boolean payChargebacks(String orderId, ClientEnum clientEnum) {
        boolean flag = false;
        try {
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
            alipayRequest.setBizContent(null);
            AlipayClient alipayClient = getAlipayClient(clientEnum);
            alipayClient.execute(alipayRequest);
            flag = true;
        } catch (AlipayApiException e) {

        }
        return flag;

    }

    @Override
    public PaySuccessParam payQuery(String orderId, ClientEnum clientEnum) {
        AlipayClient alipayClient = getAlipayClient(clientEnum);

        AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();
        alipayTradeQueryModel.setOutTradeNo(orderId);
        alipayTradeQueryRequest.setBizModel(alipayTradeQueryModel);
        try {
            AlipayTradeQueryResponse response = alipayClient.execute(alipayTradeQueryRequest);
            if (BaseConstant.TRADE_SUCCESS.equals(response.getTradeStatus())) {
                PaySuccessParam p = new PaySuccessParam();
                p.setOrderNum(response.getOutTradeNo());
                p.setPayAccount(response.getBuyerPayAmount());
                p.setPayTime(response.getSendPayDate());
                p.setOutNum(response.getTradeNo());
                return p;
            }
        } catch (AlipayApiException e) {
        }
        return null;
    }

    @Override
    public String getMiniOpenId(String id) {
        AlipayClient alipayClient = getAlipayClient(ClientEnum.MINI);
        String userId = null;
        try {
            AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
            request.setGrantType("authorization_code");
            request.setCode(id);
            AlipaySystemOauthTokenResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                userId = response.getUserId();
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return userId;
    }

    /**
     * 验签通过返回
     *
     * @return
     */
    @Override
    public Object signOk() {
        //支付宝要求成功返回 success 字符串
        return "success";
    }


    /**
     * 判断支付类型对新增开放，对修改关闭
     *
     * @param type
     * @return
     */
    @Override
    public boolean supports(String type) {
        return getName().equalsIgnoreCase(type);
    }

}
